package com.xzzz.common.base.util.easyexcel;

import cn.hutool.core.io.FileUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List;

/**
 * excel 工具类
 * <p><a href='https://easyexcel.opensource.alibaba.com/docs/current/'>官方网站</a>
 **/
public class EasyExcelUtils {

    public static void main(String[] args) {
        File excel = new File("C:\\Users\\Administrator\\Desktop\\test.xlsx");
        List<TestPojo> list = EasyExcelUtils.imports(FileUtil.getInputStream(excel), TestPojo.class);
        for (TestPojo testPojo : list) {
            System.out.println(testPojo.toString());
        }
    }

    /**
     * 同步导入, 适用于小数据量
     *
     * @param is    输入流
     * @param clazz 转换后的类
     * @return 转换后集合
     */
    public static <T> List<T> imports(InputStream is, Class<T> clazz) {
        return EasyExcel.read(is).head(clazz).autoCloseStream(false).sheet().doReadSync();
    }

    /**
     * 同步导入, 适用于小数据量
     *
     * @param is      输入流
     * @param sheetNo sheet 页码
     * @param clazz   转换后的类
     * @return 转换后集合
     */
    public static <T> List<T> imports(InputStream is, int sheetNo, Class<T> clazz) {
        return EasyExcel.read(is).head(clazz).autoCloseStream(false).sheet(sheetNo).doReadSync();
    }

    /**
     * 导出excel
     *
     * @param list      导出数据集合
     * @param sheetName 工作表的名称
     * @param clazz     实体类
     * @param response  响应体
     */
    public static <T> void export(List<T> list, String sheetName, Class<T> clazz, HttpServletResponse response) {
        export(list, sheetName, clazz, false, response);
    }


    /**
     * 导出excel
     *
     * @param list      导出数据集合
     * @param filename 工作表的名称
     * @param clazz     实体类
     * @param merge     是否合并单元格
     * @param response  响应体
     */
    public static <T> void export(List<T> list, String filename, Class<T> clazz, boolean merge, HttpServletResponse response) {
        try {
            resetResponse(filename, response);
            ServletOutputStream os = response.getOutputStream();
            ExcelWriterSheetBuilder builder = EasyExcel.write(os, clazz)
                    .autoCloseStream(false)
                    // 自动适配
                    .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                    // 大数值自动转换 防止失真
                    .registerConverter(new ExcelBigNumberConvert())
                    .sheet(filename);

//            if (merge) {
//                // 合并处理器
//                builder.registerWriteHandler(new CellMergeStrategy(list, true));
//            }
            builder.doWrite(list);
        } catch (IOException e) {
            throw new RuntimeException("导出Excel异常");
        }
    }


    /**
     * 重置响应体
     */
    private static void resetResponse(String filename, HttpServletResponse response) throws UnsupportedEncodingException {
        response.reset();

        // 百分号编码
        String percentEncodedFileName = URLEncoder.encode(filename, StandardCharsets.UTF_8.toString()).replaceAll("\\+", "%20");
        String contentDispositionValue = "attachment; filename=" +
                percentEncodedFileName +
                ";" +
                "filename*=" +
                "utf-8''" +
                percentEncodedFileName;

        response.addHeader("Access-Control-Expose-Headers", "Content-Disposition,download-filename");
        response.setHeader("Content-disposition", contentDispositionValue);
        response.setHeader("download-filename", percentEncodedFileName);
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8");
    }

//
//    /**
//     * 同步导入(数据进行校验)
//     *
//     * @param is 输入流
//     * @return 转换后集合
//     */
//    public static <T extends EasyExcelRow> List<T> importValidateExcel(InputStream is, int sheetNo, Class<T> clazz) {
////        return EasyExcelReader.builder().inputStream(is).sheetNo(sheetNo).headLineMun(1).build().read(clazz);
//
//        return EasyExcelReader.builder().inputStream(is).sheetNo(sheetNo).build().read(clazz);
//    }
//
//    /**
//     * 使用校验监听器 异步导入 同步返回
//     *
//     * @param is         输入流
//     * @param clazz      对象类型
//     * @param isValidate 是否 Validator 检验 默认为是
//     * @return 转换后集合
//     */
//    public static <T> ExcelResult<T> importExcel(InputStream is, Class<T> clazz, boolean isValidate) {
//        DefaultExcelListener<T> listener = new DefaultExcelListener<>(isValidate);
//        EasyExcel.read(is, clazz, listener).sheet().doRead();
//        return listener.getExcelResult();
//    }
//
//    /**
//     * 使用校验监听器 异步导入 同步返回
//     *
//     * @param is         输入流
//     * @param clazz      对象类型
//     * @param isValidate 是否 Validator 检验 默认为是
//     * @return 转换后集合
//     */
//    public static <T> ExcelResult<T> importExcel(InputStream is, int sheetNo, Class<T> clazz, boolean isValidate) {
//        DefaultExcelListener<T> listener = new DefaultExcelListener<>(isValidate);
//        EasyExcel.read(is, clazz, listener).sheet(sheetNo).doRead();
//        return listener.getExcelResult();
//    }
//
//    /**
//     * 使用自定义监听器 异步导入 自定义返回
//     *
//     * @param is       输入流
//     * @param clazz    对象类型
//     * @param listener 自定义监听器
//     * @return 转换后集合
//     */
//    public static <T> ExcelResult<T> importExcel(InputStream is, Class<T> clazz, ExcelListener<T> listener) {
//        EasyExcel.read(is, clazz, listener).sheet().doRead();
//        return listener.getExcelResult();
//    }
//
//
//    /**
//     * 单表多数据模板导出 模板格式为 {.属性}
//     *
//     * @param filename     文件名
//     * @param templatePath 模板路径 resource 目录下的路径包括模板文件名
//     *                     例如: excel/temp.xlsx
//     *                     重点: 模板文件必须放置到启动类对应的 resource 目录下
//     * @param data         模板需要的数据
//     */
//    public static void exportTemplate(List<Object> data, String filename, String templatePath, HttpServletResponse response) {
//        try {
//            resetResponse(filename, response);
//            Resource resource = new ClassPathResource(templatePath);
//            File templateResource = resource.getFile();
//            ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream())
//                    .withTemplate(templateResource)
//                    .autoCloseStream(false)
//                    // 大数值自动转换 防止失真
//                    .registerConverter(new ExcelBigNumberConvert())
//                    .build();
//            WriteSheet writeSheet = EasyExcel.writerSheet().build();
//            if (ObjectUtils.isEmpty(data)) {
//                throw new IllegalArgumentException("数据为空");
//            }
//            // 单表多数据导出 模板格式为 {.属性}
//            for (Object d : data) {
//                excelWriter.fill(d, writeSheet);
//            }
//            excelWriter.finish();
//        } catch (IOException e) {
//            throw new RuntimeException("导出Excel异常");
//        }
//    }
//
//    /**
//     * 多表多数据模板导出 模板格式为 {key.属性}
//     *
//     * @param filename     文件名
//     * @param templatePath 模板路径 resource 目录下的路径包括模板文件名
//     *                     例如: excel/temp.xlsx
//     *                     重点: 模板文件必须放置到启动类对应的 resource 目录下
//     * @param data         模板需要的数据
//     */
//    public static void exportTemplateMultiList(Map<String, Object> data, String filename, String templatePath, HttpServletResponse response) {
//        try {
//            resetResponse(filename, response);
//            Resource resource = new ClassPathResource(templatePath);
//            File templateResource = resource.getFile();
//            ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream())
//                    .withTemplate(templateResource)
//                    .autoCloseStream(false)
//                    // 大数值自动转换 防止失真
//                    .registerConverter(new ExcelBigNumberConvert())
//                    .build();
//            WriteSheet writeSheet = EasyExcel.writerSheet().build();
//            if (ObjectUtils.isEmpty(data)) {
//                throw new IllegalArgumentException("数据为空");
//            }
//            for (Map.Entry<String, Object> map : data.entrySet()) {
//                // 设置列表后续还有数据
//                FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
//                if (map.getValue() instanceof Collection) {
//                    // 多表导出必须使用 FillWrapper
//                    excelWriter.fill(new FillWrapper(map.getKey(), (Collection<?>) map.getValue()), fillConfig, writeSheet);
//                } else {
//                    excelWriter.fill(map.getValue(), writeSheet);
//                }
//            }
//            excelWriter.finish();
//        } catch (IOException e) {
//            throw new RuntimeException("导出Excel异常");
//        }
//    }
//
//
//    /**
//     * 解析导出值 0=男,1=女,2=未知
//     *
//     * @param propertyValue 参数值
//     * @param converterExp  翻译注解
//     * @param separator     分隔符
//     * @return 解析后值
//     */
//    public static String convertByExp(String propertyValue, String converterExp, String separator) {
//        StringBuilder propertyString = new StringBuilder();
//        String[] convertSource = converterExp.split(",");
//        for (String item : convertSource) {
//            String[] itemArray = item.split("=");
//            if (StringUtils.containsAny(propertyValue, separator)) {
//                for (String value : propertyValue.split(separator)) {
//                    if (itemArray[0].equals(value)) {
//                        propertyString.append(itemArray[1] + separator);
//                        break;
//                    }
//                }
//            } else {
//                if (itemArray[0].equals(propertyValue)) {
//                    return itemArray[1];
//                }
//            }
//        }
//        return StringUtils.stripEnd(propertyString.toString(), separator);
//    }
//
//    /**
//     * 反向解析值 男=0,女=1,未知=2
//     *
//     * @param propertyValue 参数值
//     * @param converterExp  翻译注解
//     * @param separator     分隔符
//     * @return 解析后值
//     */
//    public static String reverseByExp(String propertyValue, String converterExp, String separator) {
//        StringBuilder propertyString = new StringBuilder();
//        String[] convertSource = converterExp.split(",");
//        for (String item : convertSource) {
//            String[] itemArray = item.split("=");
//            if (StringUtils.containsAny(propertyValue, separator)) {
//                for (String value : propertyValue.split(separator)) {
//                    if (itemArray[1].equals(value)) {
//                        propertyString.append(itemArray[0] + separator);
//                        break;
//                    }
//                }
//            } else {
//                if (itemArray[1].equals(propertyValue)) {
//                    return itemArray[0];
//                }
//            }
//        }
//        return StringUtils.stripEnd(propertyString.toString(), separator);
//    }
//
//    /**
//     * 编码文件名
//     */
//    public static String encodingFilename(String filename) {
//        return IdUtils.fastSimpleUUID() + "_" + filename + ".xlsx";
//    }
}
